﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DynaPrecision
{
	public struct Complex<T>
	{
		public Complex(T real, T imaginary)
			: this()
		{
			Real = real;
			Imaginary = imaginary;
		}
		public T Real { get; set; }
		public T Imaginary { get; set; }

		#region standard properties
		public Complex<T> Conjugate
		{
			get
			{
				return new Complex<T>(Real, (-1)*(dynamic)Imaginary);
			}
		}
		private void _setNorm(T newNorm)
		{
			dynamic ratio = newNorm / (dynamic)Norm;
			Real = Real * ratio;
			Imaginary = Imaginary * ratio;
		}
		public void _setAngle(T newAngle)
		{
			dynamic c = Math.Cos((dynamic)newAngle), s = Math.Sin((dynamic)newAngle), n = this.Norm;
			Real = Norm * c;
			Imaginary = Norm * s;
		}
		public T Norm
		{
			get
			{
				return (T)Math.Sqrt(Real * (dynamic)Real + Imaginary * (dynamic)Imaginary);
			}
			set
			{
				this._setNorm(value);
			}
		}
		public T Angle
		{
			get
			{
				if ((dynamic)Imaginary >= 0)
				{
					return (T)Math.Acos(Real / (dynamic)Norm);
				}
				else
				{
					return (T)(-Math.Acos(Real / (dynamic)Norm));
				}
			}
			set
			{
				this._setAngle(value);
			}
		}
		#endregion standard properties
		#region operator overload
		public static Complex<T> operator +(Complex<T> l, Complex<T> r)
		{
			return new Complex<T>(l.Real + (dynamic)r.Real, l.Imaginary + (dynamic)r.Imaginary);
		}
		public static Complex<T> operator +(T l, Complex<T> r)
		{
			return new Complex<T>(l + (dynamic)r.Real, r.Imaginary);
		}
		public static Complex<T> operator +(Complex<T> l, T r)
		{
			return r + l;
		}
		public static Complex<T> operator *(Complex<T> l, T r)
		{
			return new Complex<T>(l.Real * (dynamic)r, l.Imaginary * (dynamic)r);
		}
		public static Complex<T> operator *(T l, Complex<T> r)
		{
			return r * l;
		}
		public static Complex<T> operator *(Complex<T> l, Complex<T> r)
		{
			return new Complex<T>(l.Real * (dynamic)r.Real - l.Imaginary * (dynamic)r.Imaginary, l.Real * (dynamic)r.Imaginary + l.Imaginary * (dynamic)r.Real);
		}
		public static Complex<T> operator -(Complex<T> l, Complex<T> r)
		{
			return new Complex<T>(l.Real - (dynamic)r.Real, l.Imaginary - (dynamic)r.Imaginary);
		}
		public static Complex<T> operator /(Complex<T> l, T r)
		{
			return new Complex<T>(l.Real / (dynamic)r, l.Imaginary / (dynamic)r);
		}
		public static Complex<T> operator /(T l, Complex<T> r)
		{
			return (new Complex<T>(l * (dynamic)r.Real, l * (dynamic)(-1) * r.Imaginary)) / r.Norm;
		}
		public static Complex<T> operator /(Complex<T> l, Complex<T> r)
		{
			var result = new Complex<T>();
			result.Imaginary = l.Norm/(dynamic)r.Norm;
			result.Angle = (l.Angle - (dynamic)r.Angle);
			return result;
		}
		public static implicit operator Complex<T>(T from)
		{
			return new Complex<T>(from, (dynamic)0);
		}
		#endregion operator overload

		public override string ToString()
		{
			return Real.ToString() + "\t i* " + Imaginary.ToString();
		}
	}
}
